//---------------------------------------------------------------------------

#ifndef ListaH
#define ListaH

#include "Nodo.h"
//---------------------------------------------------------------------------
template <class TipoDatos>
class Lista{
    public:
        Lista();
        Lista(TipoDatos *valor);
        ~Lista();
        void anadirIzquierda(TipoDatos *valor);
        void anadirDerecha(TipoDatos *valor);
        Nodo<TipoDatos> * getIzquierdo();
        Nodo<TipoDatos> * getDerecho();
        Nodo<TipoDatos> * getActual();
        Nodo<TipoDatos> * getPos(int i);
        void inicia();
        void avanza();
        void eliminarIzquierdo();
        void eliminarDerecho();
        void eliminaActual(bool borrar);
        void concatenar(Lista<TipoDatos>* lista);
        bool esFinal();
        bool estaVacia();
        int getLongitud();

    private:
        Nodo<TipoDatos> *izquierdo;
        Nodo<TipoDatos> *derecho;
        Nodo<TipoDatos> *actual;
        int longitud;

};


template <class TipoDatos>
Lista<TipoDatos>::Lista(){
    izquierdo=NULL;
    derecho=NULL;
    actual=NULL;
    longitud=0;
}

template <class TipoDatos>
Lista<TipoDatos>::Lista(TipoDatos *valor){
    Nodo<TipoDatos> *nodo=new Nodo<TipoDatos>(valor);
    izquierdo=nodo;
    derecho=nodo;
    actual=nodo;
    longitud=1;
}

template <class TipoDatos>
Lista<TipoDatos>::~Lista(){
    Nodo<TipoDatos> * aux;
    int longitudLista=longitud;
    for(int i=1;i<=longitudLista;i++){
        eliminarIzquierdo();
    }
}

template <class TipoDatos>
void Lista<TipoDatos>::anadirIzquierda(TipoDatos *valor){
    Nodo<TipoDatos> *nodo=new Nodo<TipoDatos>(valor);
    if (estaVacia())
        derecho=nodo;

    else{
        nodo->setSiguiente(izquierdo);
        izquierdo->setAnterior(nodo);
    }
    izquierdo=nodo;
    longitud++;
}

template <class TipoDatos>
void Lista<TipoDatos>::anadirDerecha(TipoDatos *valor){
    Nodo<TipoDatos> *nodo=new Nodo<TipoDatos>(valor);
    if(estaVacia())
        izquierdo=nodo;
    else{
        nodo->setAnterior(derecho);
        derecho->setSiguiente(nodo);
    }
    derecho=nodo;
    longitud++;
}

template <class TipoDatos>
Nodo<TipoDatos>* Lista<TipoDatos>::getIzquierdo(){
    if (estaVacia()) throw 1;
    else return izquierdo;
}

template <class TipoDatos>
Nodo<TipoDatos>* Lista<TipoDatos>::getDerecho(){
    if (estaVacia()) throw 1;
    else return derecho;
}

template <class TipoDatos>
Nodo<TipoDatos>* Lista<TipoDatos>::getActual(){
    if (actual==NULL) throw 1;
    else return actual;
}

template <class TipoDatos>
Nodo<TipoDatos>* Lista<TipoDatos>::getPos(int i){
    int pos=0;
    if (i>=longitud) throw 1;
    else for(inicia(); pos<i;avanza())pos++;
    return actual;
}

template <class TipoDatos> void Lista<TipoDatos>::inicia(){
  actual=izquierdo;
}

template <class TipoDatos> void Lista<TipoDatos>::avanza(){
  if(actual!=NULL) actual= actual->getSiguiente();
}

template <class TipoDatos>
bool Lista<TipoDatos>::esFinal(){
    return actual==NULL;
}

template <class TipoDatos>
void Lista<TipoDatos>::eliminarIzquierdo(){
    Nodo<TipoDatos> * aux=izquierdo;
    if(estaVacia())  throw 1;
    else{
        izquierdo=izquierdo->getSiguiente();
        if(izquierdo==NULL) derecho=NULL;
        else izquierdo->setAnterior(NULL);
        longitud--;
        delete aux;
    }
}

template <class TipoDatos>
void Lista<TipoDatos>::eliminarDerecho(){
    Nodo<TipoDatos> * aux=derecho;
    if(estaVacia())  throw 1;
    else{
        derecho=derecho->getAnterior();
        if(derecho==NULL) izquierdo=NULL;
        else derecho->setSiguiente(NULL);
        longitud--;
        delete aux;
    }
}

template <class TipoDatos> void Lista<TipoDatos>::eliminaActual(bool borrar){
  if(actual!=NULL){
    if(actual->getSiguiente()!=NULL)
       actual->getSiguiente()->setAnterior(actual->getAnterior());
    if(actual->getAnterior()!=NULL)
       actual->getAnterior()->setSiguiente(actual->getSiguiente());

    if(actual==izquierdo) izquierdo= izquierdo->getSiguiente();
    if(actual==derecho) derecho= derecho->getAnterior();

    Nodo<TipoDatos>* aux= actual->getSiguiente();
    if (borrar) delete actual; //borrar el nodo
    //actual se queda en la posicion siguiente
    actual= aux;
    longitud--;
  }
}



template <class TipoDatos>
void Lista<TipoDatos>::concatenar(Lista<TipoDatos>* lista){
    if(estaVacia()){
        izquierdo=lista->getIzquierdo();
        derecho=lista->getDerecho();
        longitud=lista->getLongitud();
    }
    else
    if(!lista->estaVacia()){
        derecho->setSiguiente(lista->getIzquierdo());
        longitud=longitud+lista->getLongitud();
        derecho=lista->getDerecho();
        lista->setLongitud(0);
    }
}

template <class TipoDatos>
bool Lista<TipoDatos>::estaVacia(){
    return (longitud==0);
}

template <class TipoDatos>
int Lista<TipoDatos>::getLongitud(){
    return longitud;
}

#endif
